package main

import (
	"bytes"
	"encoding/binary"
	"errors"
)

var ErrTooLarge = errors.New("packet too large")

const (
	BUFFERSIZE = 65535
	HEADLEN    = 12

	CMDNEW       = "NEW"
	CMDHEARTBEAT = "HB"
	CMDPACKET    = "PKT"
	CMDCLOSE     = "CLS"
)

//packet 数据结构如下
//cmd      [4]byte
//conid    int32
//PayloadLen  int32
//Payload     []byte
type packet struct {
	data []byte
	done chan bool
}

func (t *packet) Head() []byte {
	return t.data[:HEADLEN]
}

func (t *packet) Payload() []byte {
	return t.data[HEADLEN:]
}

func (t *packet) Cmd() string {
	h := bytes.TrimRight(t.Head()[0:4], string([]byte{0}))
	return string(h)
}

func (t *packet) Usrid() int {
	return int(binary.BigEndian.Uint32(t.Head()[4:8]))
}

//Head中记录的Payload长度
func (t *packet) PayloadLen() int {
	return int(binary.BigEndian.Uint32(t.Head()[8:12]))
}

func (t *packet) setHead(cmd string, usrid uint32) {

	binary.BigEndian.PutUint32(t.Head()[0:4], 0)
	if cmd != "" {
		copy(t.Head()[0:4], []byte(cmd))
	}

	binary.BigEndian.PutUint32(t.Head()[4:8], usrid)

	t.ResetPayload()
}

func (t *packet) ResetPayload() {

	binary.BigEndian.PutUint32(t.Head()[8:12], 0)
	t.data = t.data[:HEADLEN]
}

func (t *packet) AllocPayload(len uint32) {

	binary.BigEndian.PutUint32(t.Head()[8:12], len)

	t.data = t.data[:HEADLEN+len]
}

func (t *packet) Bytes() []byte {
	return t.data
}

func (t *packet) Reset() {
	t.setHead("", 0)
	t.ResetPayload()
}

/*
func (t *packet) Write(p []byte) (n int, err error) {
	l := len(t.data)
	if cap(t.data)-l < len(p) {
		panic(bytes.ErrTooLarge)
	}

	n = copy(t.data[l:cap(t.data)], p)

	t.data = t.data[:l+n]
	return
}

*/

func NewPacket(cmd string, conid uint32) *packet {
	p := &packet{data: make([]byte, HEADLEN, BUFFERSIZE), done: make(chan bool)}
	p.setHead(cmd, conid)
	return p
}

func NewEmptyPacket() *packet {
	p := &packet{data: make([]byte, HEADLEN, BUFFERSIZE), done: make(chan bool)}
	return p
}
